package com.jwsoft.manager.core.integration.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bifang.assistant.common.vo.BaseVO;
import com.bifang.engine.assistant.core.annotation.ApiService;
import com.bifang.engine.assistant.core.annotation.OpApi;
import com.bifang.engine.assistant.core.annotation.SaveOplog;
import com.bifang.engine.assistant.core.enums.*;
import com.bifang.engine.assistant.core.exception.AppException;
import com.bifang.engine.assistant.core.utils.SessionUtil;
import com.bifang.engine.cache.jetcache.utils.JetCacheUtils;
import com.bifang.engine.data.core.util.PagerUtil;
import com.bifang.engine.protect.core.annotation.NoSignCrypto;
import com.bifang.module.base.common.vo.excel.ExcelModelVO;
import com.bifang.module.base.common.vo.excel.ExcelVO;
import com.bifang.module.base.core.helper.DictHelper;
import com.bifang.module.base.core.helper.ExcelCommonHelper;
import com.bifang.module.base.core.integration.OperationPeriodIntegration;
import com.bifang.module.system.core.integration.impl.ExcelIntegrationImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jwsoft.manager.common.constant.EduCache;
import com.jwsoft.manager.common.enums.EnrollStatusFormalEnum;
import com.jwsoft.manager.common.enums.SchoolCategoryEnum;
import com.jwsoft.manager.common.enums.SchoolDictEnum;
import com.jwsoft.manager.common.vo.eduSchool.EduSchoolVO;
import com.jwsoft.manager.common.vo.eduSchoolVacancy.EduSchoolVacancyKeyVO;
import com.jwsoft.manager.common.vo.eduSchoolVacancy.EduSchoolVacancyQueryVO;
import com.jwsoft.manager.common.vo.eduSchoolVacancy.EduSchoolVacancyVO;
import com.jwsoft.manager.common.vo.eduSchoolVacancy.SchoolVacancyFirstVO;
import com.jwsoft.manager.core.dao.model.*;
import com.jwsoft.manager.core.dao.service.EduSchoolConfigService;
import com.jwsoft.manager.core.dao.service.EduSchoolService;
import com.jwsoft.manager.core.dao.service.EduSchoolVacancyService;
import com.jwsoft.manager.core.dao.service.EduStudentEnrollService;
import com.jwsoft.manager.core.integration.EduSchoolVacancyIntegration;
import com.jwsoft.manager.core.util.EduHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 学校缺额表业务实现类
 *
 * @author hhj
 * @since 2022-12-21
 */
@ApiService(funcCode = "eduSchoolVacancy", title = "学校缺额表")
public class EduSchoolVacancyIntegrationImpl implements EduSchoolVacancyIntegration {

    @Autowired
    public EduSchoolVacancyService eduSchoolVacancyService;

    @Autowired
    private DictHelper dictHelper;


    @Autowired
    private EduSchoolService eduSchoolService;

    @Autowired
    private EduSchoolConfigService eduSchoolConfigService;

    @Autowired
    private EduStudentEnrollService eduStudentEnrollService;

    @Resource
    public ExcelIntegrationImpl excelIntegration;

    @Autowired
    ExcelCommonHelper excelCommonHelper;

    @Resource
    private EduHelper eduHelper;
    @Value("${spring.servlet.multipart.location}")
    private String tempPath;

    @Override
    @OpApi(funcCode = "eduSchoolVacancy0001", title = "学校缺额表分页查询", funcType = FuncTypeEnum.query)
    public PageInfo<EduSchoolVacancyVO> getList(EduSchoolVacancyQueryVO vo) {

        List<EduSchoolVacancyVO> eduSchoolVacancyList = querySchoolVacancyInfo(vo);
        if (CollectionUtils.isEmpty(eduSchoolVacancyList)) {
            // 判断是否为空，为空则返回空参数
            return PagerUtil.createEmptyPagerInfo(vo.getPageNum(), vo.getPageSize());
        }
        // 不为空则获取分页结果
        PageInfo<EduSchoolVacancyVO> pageInfo = new PageInfo<>(eduSchoolVacancyList);
        List<EduSchoolVacancyVO> resList = pageInfo.getList();

//       转义数据字典值
        dictHelper.valueToName(resList, Arrays.asList(SchoolDictEnum.values()));
        for (EduSchoolVacancyVO eduSchoolVacancyVO : resList) {
            eduSchoolVacancyVO.setAreaName(dictHelper.getAreaNameByCode(eduSchoolVacancyVO.getAreaCode()));
        }
        return pageInfo;
    }

    @Override
    @OpApi(funcCode = "eduSchoolVacancy0002", title = "学校缺额表根据主键查询详情", funcType = FuncTypeEnum.query)
    public EduSchoolVacancyVO getById(EduSchoolVacancyKeyVO vo) {
        EduSchoolVacancy entity = eduSchoolVacancyService.getById(vo.getSchoolVacancyId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("查询不到详细信息!");
        }
        EduSchoolVacancyVO result = Convert.convert(EduSchoolVacancyVO.class, entity);
        return result;
    }
    /** 保存前统一校验*/
    @Override
    @OpApi(funcCode = "eduSchoolVacancy0003", title = "学校缺额表保存前校验", funcType = FuncTypeEnum.other ,checkPrivilege = BoolEnum.FALSE)
    public void checkSave(EduSchoolVacancyVO vo) {
        //主键为空为新增校验

        //主键不为空为修改校验
    }

    @Override
    @OpApi(funcCode = "eduSchoolVacancy0004", title = "学校缺额表新增", funcType = FuncTypeEnum.insert)
    @SaveOplog(
            operationType = "eduSchoolVacancy0004",
            operationName = "学校缺额表新增",
            dataType = "schoolVacancyId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public EduSchoolVacancyVO add(EduSchoolVacancyVO vo) {
        //保存前校验
        if (StringUtils.isBlank(vo.getSchoolId())) {
            throw new AppException("学校id不能为空");
        }
        Integer year = eduHelper.thisYear();
        EduSchoolVO eduSchoolVO = eduSchoolService.getDetail(vo.getSchoolId());
        if (eduSchoolVO == null) {
            throw new AppException("学校信息不存在");
        }
        QueryWrapper<EduSchoolVacancy> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(EduSchoolVacancy::getSchoolId, vo.getSchoolId())
                .eq(EduSchoolVacancy::getYear, year);
        if (eduSchoolVacancyService.count(queryWrapper) > 0) {
            throw new AppException("学校缺额信息已存在，请修改");
        }
        if (vo.getVacancyNum() == null) {
            vo.setVacancyNum(0);
        }
        vo.setAreaCode(eduSchoolVO.getAreaCode());
        vo.setYear(year);
        vo.setAuthStatus(AuthStatusEnum.YES.getType());
        //保存数据
        EduSchoolVacancy entity = Convert.convert(EduSchoolVacancy.class, vo);
        eduSchoolVacancyService.save(entity);
        //将主键设置回vo使操作日志可以取到
        vo.setSchoolVacancyId(entity.getSchoolVacancyId());
        clearCacheAreaCode(entity.getAreaCode());
        return vo;
    }

    @Override
    @OpApi(funcCode = "eduSchoolVacancy0005", title = "学校缺额表修改", funcType = FuncTypeEnum.update)
    @SaveOplog(
            operationType = "eduSchoolVacancy0005",
            operationName = "学校缺额表修改",
            dataType = "schoolVacancyId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public EduSchoolVacancyVO edit(EduSchoolVacancyVO vo) {
        if (ObjectUtils.isEmpty(vo.getSchoolVacancyId())) {
            throw new AppException("传入需要修改的主键不能为空!");
        }
        EduSchoolVacancy schoolVacancy = eduSchoolVacancyService.getById(vo.getSchoolVacancyId());
        if (ObjectUtils.isEmpty(schoolVacancy)) {
            throw new AppException("查询不到需要修改的信息!");
        }
        Integer year = eduHelper.thisYear();
        if (year - schoolVacancy.getYear() != 0) {
            throw new AppException("只能修改当前年度的缺额信息!");
        }
        //保存前校验
        checkSave(vo);
        //保存数据
        if (vo.getVacancyNum() != null) {
            schoolVacancy.setVacancyNum(vo.getVacancyNum());
            eduSchoolVacancyService.updateById(schoolVacancy);
            clearCacheAreaCode(schoolVacancy.getAreaCode());
        } else {
            throw new AppException("缺额数不能为空！");
        }
        return vo;
    }

    @Override
    @OpApi(funcCode = "eduSchoolVacancy0006", title = "学校缺额表单个删除", funcType = FuncTypeEnum.delete)
    @SaveOplog(
            operationType = "eduSchoolVacancy0006",
            operationName = "学校缺额表单个删除",
            dataType = "schoolVacancyId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public boolean del(EduSchoolVacancyKeyVO vo) {
        if (ObjectUtils.isEmpty(vo.getSchoolVacancyId())) {
            throw new AppException("传入需要修改的主键不能为空!");
        }
        EduSchoolVacancy schoolVacancy = eduSchoolVacancyService.getById(vo.getSchoolVacancyId());
        if (ObjectUtils.isEmpty(schoolVacancy)) {
            throw new AppException("查询不到需要删除的信息!");
        }
        Integer year = eduHelper.thisYear();
        if (year - schoolVacancy.getYear() != 0) {
            throw new AppException("只能删除当前年度的缺额信息!");
        }
        QueryWrapper<EduStudentEnroll> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(EduStudentEnroll::getYear, schoolVacancy.getYear())
                .eq(EduStudentEnroll::getSpareRegisterFlag, BoolEnum.TRUE.getType())
                .eq(EduStudentEnroll::getSchoolId, schoolVacancy.getSchoolId());
        if (eduStudentEnrollService.count(queryWrapper) > 0) {
            throw new AppException("已有报名数据，不能删除");
        }
        eduSchoolVacancyService.removeById(vo.getSchoolVacancyId());
        return true;
    }

    @Override
    @OpApi(
            funcCode = "eduSchoolVacancy0007",
            title = "初始化学校缺额信息",
            funcType = FuncTypeEnum.query,
            checkPrivilege = BoolEnum.FALSE,
            publicFlag = BoolEnum.TRUE)
    public PageInfo<EduSchoolVacancyVO> SchoolVacancyFirstList(SchoolVacancyFirstVO vo) {
        //判断年度不能为空
        Integer year = eduHelper.thisYear();
        if (vo.getYear() == null) {
            vo.setYear(year);
        } else {
            if (vo.getYear() - year != 0) {
                throw new AppException("历史年度数据不能初始化");
            }
        }

        if (StringUtils.isBlank(vo.getAreaCode())) {
            vo.setAreaCode(SessionUtil.getAreaCode());
        }
        //判断年度是否存在数据
        QueryWrapper<EduSchoolVacancy> queryWrapperVc = new QueryWrapper<>();
        queryWrapperVc.lambda()
                .eq(EduSchoolVacancy::getYear, vo.getYear())
                .eq(StringUtils.isNotBlank(vo.getAreaCode()), EduSchoolVacancy::getAreaCode, vo.getAreaCode());
        List<EduSchoolVacancy> schoolVacancyList = eduSchoolVacancyService.list(queryWrapperVc);
        if (schoolVacancyList.size() != 0) {
            throw new AppException("该年度已有数据");
        }
        //获取学校数据
        List<String> schoolCategoryList = new ArrayList<>();
        schoolCategoryList.add(SchoolCategoryEnum.PRIMARY.getType());
        schoolCategoryList.add(SchoolCategoryEnum.JUNIOR.getType());
        QueryWrapper<EduSchool> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(EduSchool::getStatus, BoolEnum.TRUE.getType())
                .eq(EduSchool::getRecruitStatus, BoolEnum.FALSE.getType())
                .eq(EduSchool::getVirtualFlag, BoolEnum.FALSE.getType())
                .eq(StringUtils.isNotBlank(vo.getAreaCode()), EduSchool::getAreaCode, vo.getAreaCode())
                .in(EduSchool::getSchoolCategory, schoolCategoryList)
                .orderByAsc(EduSchool::getOrderBy).orderByAsc(EduSchool::getSchoolCategory).orderByAsc(EduSchool::getSchoolNum);
        List<EduSchool> schoolList = eduSchoolService.list(queryWrapper);

        if (CollectionUtils.isEmpty(schoolList)) {
            throw new AppException("该年度无学校数据");
        }
        List<EduSchoolVacancy> saveList = new ArrayList<>();
        List<String> areaCodelist = new ArrayList<>();
        for (EduSchool eduSchool : schoolList) {
            //EduSchoolVacancy eduSchoolVacancy=Convert.convert(EduSchoolVacancy.class,eduSchool);
            EduSchoolVacancy eduSchoolVacancy = new EduSchoolVacancy();
            eduSchoolVacancy.setSchoolVacancyId(IdUtil.simpleUUID());//主键
            eduSchoolVacancy.setYear(vo.getYear());
            eduSchoolVacancy.setSchoolId(eduSchool.getOrgId());
            eduSchoolVacancy.setVacancyNum(0);
            eduSchoolVacancy.setAreaCode(eduSchool.getAreaCode());
            eduSchoolVacancy.setAuthStatus(AuthStatusEnum.YES.getType());
            eduSchoolVacancy.setVacancyNum((int) getVacancyNum(eduSchool.getOrgId(),vo.getYear()));
            saveList.add(eduSchoolVacancy);
            if (!areaCodelist.contains(eduSchool.getAreaCode())) {
                areaCodelist.add(eduSchool.getAreaCode());
            }
        }
        eduSchoolVacancyService.saveBatch(saveList);
        for (String areaCode : areaCodelist) {
            clearCacheAreaCode(areaCode);
        }

        return null;
    }

    private void clearCacheAreaCode(String areaCode) {
        if (StringUtils.isNotBlank(areaCode)) {
            Cache cache = JetCacheUtils.create(EduCache.EDU_SCHOOL_areaCode, CacheType.BOTH);
            if (cache != null) {
                cache.remove(areaCode);
            }
        }
    }
    private List<EduSchoolVacancyVO> querySchoolVacancyInfo(EduSchoolVacancyQueryVO vo) {
        boolean permissionFlag = true;
        if (vo.getPermissionFlag() != null) {
            permissionFlag = vo.getPermissionFlag();
        }
        if (!ObjectUtils.isEmpty(vo.getSearchText())) {
            vo.setSchoolName(vo.getSearchText());
        }
        if (StringUtils.isNotBlank(vo.getShortName())) {
            vo.setShortName(Convert.toDBC(vo.getShortName()));
        }
        if (StringUtils.isNotBlank(vo.getSchoolName())) {
            vo.setSchoolName(Convert.toDBC(vo.getSchoolName()));
        }
        if (vo.getYear() == null) {
            vo.setYear(eduHelper.thisYear());
        }
        if (StringUtils.isBlank(vo.getAreaCode())) {
            vo.setAreaCode(SessionUtil.getAreaCode());
        }
        Map<String, Object> queryMap = BeanUtil.beanToMap(vo, false, true);
        Set<String> systemPrivileges = SessionUtil.getSystemPrivileges();
        if (!permissionFlag
                || systemPrivileges.contains(SysPermissionEnum.allorg.getType())
                || systemPrivileges.contains(SysPermissionEnum.superadmin.getType())) {

        } else {
            queryMap.put("userId", SessionUtil.getUserId());
        }

        // 开启分页
        if (vo.getPageNum() == null || vo.getPageSize() == null) {
            //如果不传入分页参数，默认最大取1000条
            vo.setPageNum(1);
            vo.setPageSize(50);
        }
        PageHelper.startPage(vo.getPageNum(), vo.getPageSize());
        return eduSchoolVacancyService.selectSchoolVacancyList(queryMap);
    }

    //计算缺额人数
    private long getVacancyNum(String schoolId, Integer year) {
        QueryWrapper<EduSchoolConfig> configQueryWrapper = new QueryWrapper<>();
        configQueryWrapper.lambda().select(EduSchoolConfig::getEnrolment)
                .eq(EduSchoolConfig::getSchoolId, schoolId)
                .eq(EduSchoolConfig::getAuthStatus, AuthStatusEnum.YES.getType())
                .eq(EduSchoolConfig::getStatus, BoolEnum.TRUE.getType())
                .eq(EduSchoolConfig::getYear, year);
        EduSchoolConfig eduSchoolConfig = eduSchoolConfigService.getOne(configQueryWrapper, false);
        //计划人数
        Integer enrolment = 0;
        if (eduSchoolConfig != null) {
            enrolment = eduSchoolConfig.getEnrolment() == null ? 0 : eduSchoolConfig.getEnrolment();
        }
        if (enrolment == 0) {
            return 0;
        }
        //已报名人数
        List<String> enrollStatusList = new ArrayList<>();
        enrollStatusList.add(EnrollStatusFormalEnum.hy.getType());
        enrollStatusList.add(EnrollStatusFormalEnum.fs.getType());
        enrollStatusList.add(EnrollStatusFormalEnum.dsh.getType());
        enrollStatusList.add(EnrollStatusFormalEnum.dlq.getType());
        enrollStatusList.add(EnrollStatusFormalEnum.lq.getType());
        QueryWrapper<EduStudentEnroll> lqQuery = new QueryWrapper<>();
        lqQuery.lambda().in(EduStudentEnroll::getEnrollStatus, enrollStatusList)
                .eq(EduStudentEnroll::getYear, year)
                .eq(EduStudentEnroll::getAdmitFlag, BoolEnum.TRUE.getType())
                .eq(EduStudentEnroll::getSchoolId, schoolId);
        long count = eduStudentEnrollService.count(lqQuery);
        long qers = enrolment - count;
        if (qers >= 0) {
            return qers;
        } else {
            return 0;
        }
    }


    @Override
    @OpApi(funcCode = "eduSchoolVacancy0008", title = "学校缺额信息导出", funcType = FuncTypeEnum.other ,checkPrivilege = BoolEnum.FALSE)
    @NoSignCrypto
    public void downloadData(EduSchoolVacancyQueryVO vo, HttpServletResponse response) {
        ExcelVO excelVO = new ExcelVO();
        excelVO.setModelCode(vo.getModelCode());
        ExcelModelVO excelModelVO=excelIntegration.getModel(excelVO);

        String destFilePath = this.tempPath + "/" + IdUtil.fastSimpleUUID() + "." + excelModelVO.getExcelType();
        int pageNum=1;
        setData(excelModelVO,null,destFilePath,vo,pageNum);
        String fileName=vo.getFileName();
        if (StringUtils.isBlank(fileName)) {
            fileName =
                    excelModelVO.getModelName()
                            + "_"
                            + DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN)
                            + "."
                            + (StringUtils.isBlank(excelModelVO.getExcelType())
                            ? "xls"
                            : excelModelVO.getExcelType());
        }
        File file = FileUtil.file(destFilePath);
        BufferedInputStream in = null;
        try {
            in = FileUtil.getInputStream(file);
            ServletUtil.write(response, in, "application/octet-stream;charset=utf-8", fileName);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(in!=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            FileUtil.del(destFilePath);
        }




    }

    @Override
    @OpApi(funcCode = "eduSchoolVacancy0009", title = "当前年度学校缺额一键清除", funcType = FuncTypeEnum.delete)
    public boolean delAll(EduSchoolVacancyQueryVO vo) {
        Integer year = eduHelper.thisYear();
        if (StringUtils.isBlank(vo.getAreaCode())) {
            vo.setAreaCode(SessionUtil.getAreaCode());
        }
        QueryWrapper<EduStudentEnroll> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(EduStudentEnroll::getYear, year)
                .eq(EduStudentEnroll::getSpareRegisterFlag, BoolEnum.TRUE.getType())
                .eq(EduStudentEnroll::getAreaCode, vo.getAreaCode());
        if (eduStudentEnrollService.count(queryWrapper) > 0) {
            throw new AppException("已有报名数据，不能一键清除");
        }
        LambdaQueryWrapper<EduSchoolVacancy> queryWrapperVc = new LambdaQueryWrapper<>();
        queryWrapperVc.eq(EduSchoolVacancy::getYear, year)
                .eq(EduSchoolVacancy::getAreaCode, vo.getAreaCode());
        ;
        eduSchoolVacancyService.remove(queryWrapperVc);
        return true;

    }

    private void setData(ExcelModelVO excelModelVO, ExcelWriter excelWriter, String destFilePath, EduSchoolVacancyQueryVO vo, int pageNum){
        vo.setPageNum(pageNum);
        vo.setPageSize(500);
        boolean closeFlag = false;
        try {
            PageInfo<EduSchoolVacancyVO> pageInfo= getList(vo);
            String total=String.valueOf(pageInfo.getTotal());
            List<Map<String,Object>> list=new ArrayList<>();
            if(!CollectionUtils.isEmpty(pageInfo.getList())){
                for(EduSchoolVacancyVO eduSchoolVacancyVO:pageInfo.getList()){
                    list.add(BeanUtil.beanToMap(eduSchoolVacancyVO,false,true));
                }
            }
            if(pageNum==1){
                if(excelWriter==null){
                    excelWriter=excelCommonHelper.createExcelWriter(excelModelVO,destFilePath,Integer.parseInt(total));
                }
                excelCommonHelper.writeMap(excelWriter,list);
            }else{
                excelCommonHelper.writeMap(excelWriter,list);
            }
            if(pageInfo.isHasNextPage()){
                pageNum=pageNum+1;
                setData(excelModelVO,excelWriter,destFilePath,vo,pageNum);
            }else {
                closeFlag = true;
            }
        }catch (AppException appEx){
            throw appEx;
        }catch (Exception e){
            throw new AppException("调用自定义写入服务异常:" + e.getMessage());
        }finally {
            if(closeFlag&&excelWriter!=null){
               excelWriter.close();
            }
        }
    }


}
